<html>
 <head>
  <meta charset="utf-8"/>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"/>
  <title>
   Python黑魔法，一行实现并行化  | 数螺 | NAUT IDEA
  </title>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet"/>
  <link href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
  <style type="text/css">
   #xmain img {
                  max-width: 100%;
                  display: block;
                  margin-top: 10px;
                  margin-bottom: 10px;
                }

                #xmain p {
                    line-height:150%;
                    font-size: 16px;
                    margin-top: 20px;
                }

                #xmain h2 {
                    font-size: 24px;
                }

                #xmain h3 {
                    font-size: 20px;
                }

                #xmain h4 {
                    font-size: 18px;
                }


                .header {
	           background-color: #0099ff;
	           color: #ffffff;
	           margin-bottom: 20px;
	        }

	        .header p {
                  margin: 0px;
                  padding: 10px 0;
                  display: inline-block;  
                  vertical-align: middle;
                  font-size: 16px;
               }

               .header a {
                 color: white;
               }

              .header img {
                 height: 25px;
              }
  </style>
  <script src="http://cdn.bootcss.com/jquery/3.0.0/jquery.min.js">
  </script>
  <script src="http://nautstatic-10007657.file.myqcloud.com/static/css/readability.min.js" type="text/javascript">
  </script>
  <script type="text/javascript">
   $(document).ready(function() {
                 var loc = document.location;
                 var uri = {
                  spec: "http://dataunion.org/24295.html",
                  host: "http://dataunion.org",
                  prePath: "http://dataunion.org",
                  scheme: "http",
                  pathBase: "http://dataunion.org/"
                 };
    
                 var documentClone = document.cloneNode(true);
                 var article = new Readability(uri, documentClone).parse();
     
                 document.getElementById("xmain").innerHTML = article.content;
                });
  </script>
  <!-- 1466460581: Accept with keywords: (title(0.4):Python,社区,并行,数盟,化, topn(0.266666666667):社区,原作者,队列,职业规划,数盟,参数传递,行业资讯,任务,数据挖掘,结果,Python,并行,对象,例子,密集型,文章,基础架构,方法,教程,函数,python,问题,可视化,进程,编程语言,缩略图,代码,程序,线程,模块).-->
 </head>
 <body onload="">
  <div class="header">
   <div class="container">
    <div class="row">
     <div class="col-xs-6 col-sm-6 text-left">
      <a href="/databee">
       <img src="http://nautidea-10007657.cos.myqcloud.com/logo_white.png"/>
      </a>
      <a href="/databee">
       <p>
        数螺
       </p>
      </a>
     </div>
     <div class="hidden-xs col-sm-6 text-right">
      <p>
       致力于数据科学的推广和知识传播
      </p>
     </div>
    </div>
   </div>
  </div>
  <div class="container text-center">
   <h1>
    Python黑魔法，一行实现并行化
   </h1>
  </div>
  <div class="container" id="xmain">
   ﻿﻿
   <title>
    Python黑魔法，一行实现并行化 | 数盟社区
   </title>
   <!-- All in One SEO Pack 2.2.7.6.2 by Michael Torbert of Semper Fi Web Design[32,64] -->
   <!-- /all in one seo pack -->
   <!--
<div align="center">
<a href="http://strata.oreilly.com.cn/hadoop-big-data-cn?cmp=mp-data-confreg-home-stcn16_dataunion_pc" target="_blank"><img src="http://dataunion.org/wp-content/uploads/2016/05/stratabj.jpg"/ ></a>
</div>
-->
   <header id="header-web">
    <div class="header-main">
     <hgroup class="logo">
      <h1>
       <a href="http://dataunion.org/" rel="home" title="数盟社区">
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/logo.png"/>
       </a>
      </h1>
     </hgroup>
     <!--logo-->
     <nav class="header-nav">
      <ul class="menu" id="menu-%e4%b8%bb%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-71" id="menu-item-71">
        <a href="http://dataunion.org/category/events" title="events">
         活动
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22457" id="menu-item-22457">
          <a href="http://dataunion.org/2016timeline">
           2016档期
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22459" id="menu-item-22459">
          <a href="http://dataunion.org/category/parterc">
           合作会议
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor menu-item-has-children menu-item-20869" id="menu-item-20869">
        <a href="http://dataunion.org/category/tech" title="articles">
         文章
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20867" id="menu-item-20867">
          <a href="http://dataunion.org/category/tech/base" title="base">
           基础架构
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3302" id="menu-item-3302">
          <a href="http://dataunion.org/category/tech/ai" title="ai">
           人工智能
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3303" id="menu-item-3303">
          <a href="http://dataunion.org/category/tech/analysis" title="analysis">
           数据分析
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21920" id="menu-item-21920">
          <a href="http://dataunion.org/category/tech/dm">
           数据挖掘
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-3314" id="menu-item-3314">
          <a href="http://dataunion.org/category/tech/viz" title="viz">
           可视化
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-3305" id="menu-item-3305">
          <a href="http://dataunion.org/category/tech/devl" title="devl">
           编程语言
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-20876" id="menu-item-20876">
        <a href="http://dataunion.org/category/industry">
         行业
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-16328" id="menu-item-16328">
          <a href="http://dataunion.org/category/industry/case" title="case">
           行业应用
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-2112" id="menu-item-2112">
          <a href="http://dataunion.org/category/industry/demo" title="demo">
           Demo展示
          </a>
         </li>
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21562" id="menu-item-21562">
          <a href="http://dataunion.org/category/industry/news">
           行业资讯
          </a>
         </li>
        </ul>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-311" id="menu-item-311">
        <a href="http://dataunion.org/category/sources" title="sources">
         资源
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20870" id="menu-item-20870">
        <a href="http://dataunion.org/category/books" title="book">
         图书
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-21363" id="menu-item-21363">
        <a href="http://dataunion.org/category/training">
         课程
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children menu-item-21853" id="menu-item-21853">
        <a href="http://dataunion.org/category/jobs">
         职位
        </a>
        <ul class="sub-menu">
         <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-22050" id="menu-item-22050">
          <a href="http://dataunion.org/category/career">
           职业规划
          </a>
         </li>
        </ul>
       </li>
      </ul>
     </nav>
     <!--header-nav-->
    </div>
   </header>
   <!--header-web-->
   <div id="main">
    <div id="soutab">
     <form action="http://dataunion.org/" class="search" method="get">
     </form>
    </div>
    <div id="container">
     <nav id="mbx">
      当前位置：
      <a href="http://dataunion.org">
       首页
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech">
       文章
      </a>
      &gt;
      <a href="http://dataunion.org/category/tech/devl">
       编程语言
      </a>
      &gt;  正文
     </nav>
     <!--mbx-->
     <article class="content">
      <header align="centre" class="contenttitle">
       <div class="mscc">
        <h1 class="mscctitle">
         <a href="http://dataunion.org/24295.html">
          Python黑魔法，一行实现并行化
         </a>
        </h1>
        <address class="msccaddress ">
         <em>
          1,130 次阅读 -
         </em>
         <a href="http://dataunion.org/category/tech/devl" rel="category tag">
          编程语言
         </a>
        </address>
       </div>
      </header>
      <div class="content-text">
       <p>
        原作者: zhangzhibo 译
        <span class="pipe">
         |
        </span>
        来自: 运维帮
       </p>
       <div>
        Python 在程序并行化方面多少有些声名狼藉。撇开技术上的问题，例如线程的实现和 GIL，我觉得错误的教学指导才是主要问题。常见的经典 Python 多线程、多进程教程多显得偏“重”。而且往往隔靴搔痒，没有深入探讨日常工作中最有用的内容。
       </div>
       <div>
       </div>
       <div>
        传统的例子
       </div>
       <div>
        简单搜索下“Python 多线程教程”，不难发现几乎所有的教程都给出涉及类和队列的例子：
       </div>
       <div>
       </div>
       <div>
        #Example.py
       </div>
       <div>
        ”’
       </div>
       <div>
        Standard Producer/Consumer Threading Pattern
       </div>
       <div>
        ”’
       </div>
       <div>
       </div>
       <div>
        import time
       </div>
       <div>
        import threading
       </div>
       <div>
        import Queue
       </div>
       <div>
       </div>
       <div>
        class Consumer(threading.Thread):
       </div>
       <div>
        def __init__(self, queue):
       </div>
       <div>
        threading.Thread.__init__(self)
       </div>
       <div>
        self._queue = queue
       </div>
       <div>
       </div>
       <div>
        def run(self):
       </div>
       <div>
        while True:
       </div>
       <div>
        # queue.get() blocks the current thread until
       </div>
       <div>
        # an item is retrieved.
       </div>
       <div>
        msg = self._queue.get()
       </div>
       <div>
        # Checks if the current message is
       </div>
       <div>
        # the “Poison Pill”
       </div>
       <div>
        if isinstance(msg, str) and msg == ‘quit’:
       </div>
       <div>
        # if so, exists the loop
       </div>
       <div>
        break
       </div>
       <div>
        # “Processes” (or in our case, prints) the queue item
       </div>
       <div>
        print “I’m a thread, and I received %s!!” % msg
       </div>
       <div>
        # Always be friendly!
       </div>
       <div>
        print ‘Bye byes!’
       </div>
       <div>
       </div>
       <div>
        def Producer():
       </div>
       <div>
        # Queue is used to share items between
       </div>
       <div>
        # the threads.
       </div>
       <div>
        queue = Queue.Queue()
       </div>
       <div>
       </div>
       <div>
        # Create an instance of the worker
       </div>
       <div>
        worker = Consumer(queue)
       </div>
       <div>
        # start calls the internal run() method to
       </div>
       <div>
        # kick off the thread
       </div>
       <div>
        worker.start()
       </div>
       <div>
       </div>
       <div>
        # variable to keep track of when we started
       </div>
       <div>
        start_time = time.time()
       </div>
       <div>
        # While under 5 seconds..
       </div>
       <div>
        while time.time() – start_time &lt; 5:
       </div>
       <div>
        # “Produce” a piece of work and stick it in
       </div>
       <div>
        # the queue for the Consumer to process
       </div>
       <div>
        queue.put(‘something at %s’ % time.time())
       </div>
       <div>
        # Sleep a bit just to avoid an absurd number of messages
       </div>
       <div>
        time.sleep(1)
       </div>
       <div>
       </div>
       <div>
        # This the “poison pill” method of killing a thread.
       </div>
       <div>
        queue.put(‘quit’)
       </div>
       <div>
        # wait for the thread to close down
       </div>
       <div>
        worker.join()
       </div>
       <div>
       </div>
       <div>
        if __name__ == ‘__main__’:
       </div>
       <div>
        Producer()
       </div>
       <div>
       </div>
       <div>
        哈，看起来有些像 Java 不是吗？
       </div>
       <div>
       </div>
       <div>
        我并不是说使用生产者/消费者模型处理多线程/多进程任务是错误的（事实上，这一模型自有其用武之地）。只是，处理日常脚本任务时我们可以使用更有效率的模型。
       </div>
       <div>
       </div>
       <div>
        问题在于…
       </div>
       <div>
       </div>
       <div>
        首先，你需要一个样板类；
       </div>
       <div>
        其次，你需要一个队列来传递对象；
       </div>
       <div>
        而且，你还需要在通道两端都构建相应的方法来协助其工作（如果需想要进行双向通信或是保存结果还需要再引入一个队列）。
       </div>
       <div>
       </div>
       <div>
        worker 越多，问题越多
       </div>
       <div>
       </div>
       <div>
        按照这一思路，你现在需要一个 worker 线程的线程池。下面是 一篇 IBM 经典教程 中的例子——在进行网页检索时通过多线程进行加速。
       </div>
       <div>
       </div>
       <div>
        #Example2.py
       </div>
       <div>
        ”’
       </div>
       <div>
        A more realistic thread pool example
       </div>
       <div>
        ”’
       </div>
       <div>
       </div>
       <div>
        import time
       </div>
       <div>
        import threading
       </div>
       <div>
        import Queue
       </div>
       <div>
        import urllib2
       </div>
       <div>
       </div>
       <div>
        class Consumer(threading.Thread):
       </div>
       <div>
        def __init__(self, queue):
       </div>
       <div>
        threading.Thread.__init__(self)
       </div>
       <div>
        self._queue = queue
       </div>
       <div>
       </div>
       <div>
        def run(self):
       </div>
       <div>
        while True:
       </div>
       <div>
        content = self._queue.get()
       </div>
       <div>
        if isinstance(content, str) and content == ‘quit’:
       </div>
       <div>
        break
       </div>
       <div>
        response = urllib2.urlopen(content)
       </div>
       <div>
        print ‘Bye byes!’
       </div>
       <div>
       </div>
       <div>
        def Producer():
       </div>
       <div>
        urls = [
       </div>
       <div>
        ‘http://www.python.org’, ‘http://www.yahoo.com’
       </div>
       <div>
        ‘http://www.scala.org’, ‘http://www.google.com’
       </div>
       <div>
        # etc..
       </div>
       <div>
        ]
       </div>
       <div>
        queue = Queue.Queue()
       </div>
       <div>
        worker_threads = build_worker_pool(queue, 4)
       </div>
       <div>
        start_time = time.time()
       </div>
       <div>
       </div>
       <div>
        # Add the urls to process
       </div>
       <div>
        for url in urls:
       </div>
       <div>
        queue.put(url)
       </div>
       <div>
        # Add the poison pillv
       </div>
       <div>
        for worker in worker_threads:
       </div>
       <div>
        queue.put(‘quit’)
       </div>
       <div>
        for worker in worker_threads:
       </div>
       <div>
        worker.join()
       </div>
       <div>
       </div>
       <div>
        print ‘Done! Time taken: {}’.format(time.time() – start_time)
       </div>
       <div>
       </div>
       <div>
        def build_worker_pool(queue, size):
       </div>
       <div>
        workers = []
       </div>
       <div>
        for _ in range(size):
       </div>
       <div>
        worker = Consumer(queue)
       </div>
       <div>
        worker.start()
       </div>
       <div>
        workers.append(worker)
       </div>
       <div>
        return workers
       </div>
       <div>
       </div>
       <div>
        if __name__ == ‘__main__’:
       </div>
       <div>
        Producer()
       </div>
       <div>
       </div>
       <div>
        这段代码能正确的运行，但仔细看看我们需要做些什么：构造不同的方法、追踪一系列的线程，还有为了解决恼人的死锁问题，我们需要进行一系列的 join 操作。这还只是开始……
       </div>
       <div>
       </div>
       <div>
        至此我们回顾了经典的多线程教程，多少有些空洞不是吗？样板化而且易出错，这样事倍功半的风格显然不那么适合日常使用，好在我们还有更好的方法。
       </div>
       <div>
       </div>
       <div>
        何不试试 map
       </div>
       <div>
       </div>
       <div>
        map 这一小巧精致的函数是简捷实现 Python 程序并行化的关键。map 源于 Lisp 这类函数式编程语言。它可以通过一个序列实现两个函数之间的映射。
       </div>
       <div>
       </div>
       <div>
        urls = [‘http://www.yahoo.com’, ‘http://www.reddit.com’]
       </div>
       <div>
        results = map(urllib2.urlopen, urls)
       </div>
       <div>
       </div>
       <div>
        上面的这两行代码将 urls 这一序列中的每个元素作为参数传递到 urlopen 方法中，并将所有结果保存到 results 这一列表中。其结果大致相当于：
       </div>
       <div>
       </div>
       <div>
        results = []
       </div>
       <div>
        for url in urls:
       </div>
       <div>
        results.append(urllib2.urlopen(url))
       </div>
       <div>
       </div>
       <div>
        map 函数一手包办了序列操作、参数传递和结果保存等一系列的操作。
       </div>
       <div>
       </div>
       <div>
        为什么这很重要呢？这是因为借助正确的库，map 可以轻松实现并行化操作。
       </div>
       <div>
        <p>
         <a href="http://attach.dataguru.cn/attachments/portal/201605/25/223619qdgrg4gt1gn1qr4g.png" target="_blank">
          <img src="http://attach.dataguru.cn/attachments/portal/201605/25/223619qdgrg4gt1gn1qr4g.png"/>
         </a>
        </p>
       </div>
       <div>
        在 Python 中有个两个库包含了 map 函数： multiprocessing 和它鲜为人知的子库 multiprocessing.dummy.
       </div>
       <div>
       </div>
       <div>
        这里多扯两句： multiprocessing.dummy？ mltiprocessing 库的线程版克隆？这是虾米？即便在 multiprocessing 库的官方文档里关于这一子库也只有一句相关描述。而这句描述译成人话基本就是说:”嘛，有这么个东西，你知道就成.”相信我，这个库被严重低估了！
       </div>
       <div>
       </div>
       <div>
        dummy 是 multiprocessing 模块的完整克隆，唯一的不同在于 multiprocessing 作用于进程，而 dummy 模块作用于线程（因此也包括了 Python 所有常见的多线程限制）。
       </div>
       <div>
        所以替换使用这两个库异常容易。你可以针对 IO 密集型任务和 CPU 密集型任务来选择不同的库。
       </div>
       <div>
       </div>
       <div>
        动手尝试
       </div>
       <div>
       </div>
       <div>
        使用下面的两行代码来引用包含并行化 map 函数的库：
       </div>
       <div>
       </div>
       <div>
        from multiprocessing import Pool
       </div>
       <div>
        from multiprocessing.dummy import Pool as ThreadPool
       </div>
       <div>
       </div>
       <div>
        实例化 Pool 对象：
       </div>
       <div>
       </div>
       <div>
        pool = ThreadPool()
       </div>
       <div>
       </div>
       <div>
        这条简单的语句替代了 example2.py 中 build_worker_pool 函数 7 行代码的工作。它生成了一系列的 worker 线程并完成初始化工作、将它们储存在变量中以方便访问。
       </div>
       <div>
       </div>
       <div>
        Pool 对象有一些参数，这里我所需要关注的只是它的第一个参数：processes. 这一参数用于设定线程池中的线程数。其默认值为当前机器 CPU 的核数。
       </div>
       <div>
       </div>
       <div>
        一般来说，执行 CPU 密集型任务时，调用越多的核速度就越快。但是当处理网络密集型任务时，事情有有些难以预计了，通过实验来确定线程池的大小才是明智的。
       </div>
       <div>
       </div>
       <div>
        pool = ThreadPool(4) # Sets the pool size to 4
       </div>
       <div>
       </div>
       <div>
        线程数过多时，切换线程所消耗的时间甚至会超过实际工作时间。对于不同的工作，通过尝试来找到线程池大小的最优值是个不错的主意。
       </div>
       <div>
       </div>
       <div>
        创建好 Pool 对象后，并行化的程序便呼之欲出了。我们来看看改写后的 example2.py
       </div>
       <div>
       </div>
       <div>
        import urllib2
       </div>
       <div>
        from multiprocessing.dummy import Pool as ThreadPool
       </div>
       <div>
       </div>
       <div>
        urls = [
       </div>
       <div>
        ‘http://www.python.org’,
       </div>
       <div>
        ‘http://www.python.org/about/’,
       </div>
       <div>
        ‘http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html’,
       </div>
       <div>
        ‘http://www.python.org/doc/’,
       </div>
       <div>
        ‘http://www.python.org/download/’,
       </div>
       <div>
        ‘http://www.python.org/getit/’,
       </div>
       <div>
        ‘http://www.python.org/community/’,
       </div>
       <div>
        ‘https://wiki.python.org/moin/’,
       </div>
       <div>
        ‘http://planet.python.org/’,
       </div>
       <div>
        ‘https://wiki.python.org/moin/LocalUserGroups’,
       </div>
       <div>
        ‘http://www.python.org/psf/’,
       </div>
       <div>
        ‘http://docs.python.org/devguide/’,
       </div>
       <div>
        ‘http://www.python.org/community/awards/’
       </div>
       <div>
        # etc..
       </div>
       <div>
        ]
       </div>
       <div>
       </div>
       <div>
        # Make the Pool of workers
       </div>
       <div>
        pool = ThreadPool(4)
       </div>
       <div>
        # Open the urls in their own threads
       </div>
       <div>
        # and return the results
       </div>
       <div>
        results = pool.map(urllib2.urlopen, urls)
       </div>
       <div>
        #close the pool and wait for the work to finish
       </div>
       <div>
        pool.close()
       </div>
       <div>
        pool.join()
       </div>
       <div>
       </div>
       <div>
        实际起作用的代码只有 4 行，其中只有一行是关键的。map 函数轻而易举的取代了前文中超过 40 行的例子。为了更有趣一些，我统计了不同方法、不同线程池大小的耗时情况。
       </div>
       <div>
       </div>
       <div>
        # results = []
       </div>
       <div>
        # for url in urls:
       </div>
       <div>
        #   result = urllib2.urlopen(url)
       </div>
       <div>
        #   results.append(result)
       </div>
       <div>
       </div>
       <div>
        # # ——- VERSUS ——- #
       </div>
       <div>
       </div>
       <div>
        # # ——- 4 Pool ——- #
       </div>
       <div>
        # pool = ThreadPool(4)
       </div>
       <div>
        # results = pool.map(urllib2.urlopen, urls)
       </div>
       <div>
       </div>
       <div>
        # # ——- 8 Pool ——- #
       </div>
       <div>
       </div>
       <div>
        # pool = ThreadPool(8)
       </div>
       <div>
        # results = pool.map(urllib2.urlopen, urls)
       </div>
       <div>
       </div>
       <div>
        # # ——- 13 Pool ——- #
       </div>
       <div>
       </div>
       <div>
        # pool = ThreadPool(13)
       </div>
       <div>
        # results = pool.map(urllib2.urlopen, urls)
       </div>
       <div>
       </div>
       <div>
        结果：
       </div>
       <div>
       </div>
       <div>
        #        Single thread:  14.4 Seconds
       </div>
       <div>
        #               4 Pool:   3.1 Seconds
       </div>
       <div>
        #               8 Pool:   1.4 Seconds
       </div>
       <div>
        #              13 Pool:   1.3 Seconds
       </div>
       <div>
       </div>
       <div>
        很棒的结果不是吗？这一结果也说明了为什么要通过实验来确定线程池的大小。在我的机器上当线程池大小大于 9 带来的收益就十分有限了。
       </div>
       <div>
       </div>
       <div>
        另一个真实的例子
       </div>
       <div>
       </div>
       <div>
        生成上千张图片的缩略图
       </div>
       <div>
        这是一个 CPU 密集型的任务，并且十分适合进行并行化。
       </div>
       <div>
       </div>
       <div>
        基础单进程版本
       </div>
       <div>
       </div>
       <div>
        import os
       </div>
       <div>
        import PIL
       </div>
       <div>
       </div>
       <div>
        from multiprocessing import Pool
       </div>
       <div>
        from PIL import Image
       </div>
       <div>
       </div>
       <div>
        SIZE = (75,75)
       </div>
       <div>
        SAVE_DIRECTORY = ‘thumbs’
       </div>
       <div>
       </div>
       <div>
        def get_image_paths(folder):
       </div>
       <div>
        return (os.path.join(folder, f)
       </div>
       <div>
        for f in os.listdir(folder)
       </div>
       <div>
        if ‘jpeg’ in f)
       </div>
       <div>
       </div>
       <div>
        def create_thumbnail(filename):
       </div>
       <div>
        im = Image.open(filename)
       </div>
       <div>
        im.thumbnail(SIZE, Image.ANTIALIAS)
       </div>
       <div>
        base, fname = os.path.split(filename)
       </div>
       <div>
        save_path = os.path.join(base, SAVE_DIRECTORY, fname)
       </div>
       <div>
        im.save(save_path)
       </div>
       <div>
       </div>
       <div>
        if __name__ == ‘__main__’:
       </div>
       <div>
        folder = os.path.abspath(
       </div>
       <div>
        ’11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840′)
       </div>
       <div>
        os.mkdir(os.path.join(folder, SAVE_DIRECTORY))
       </div>
       <div>
       </div>
       <div>
        images = get_image_paths(folder)
       </div>
       <div>
       </div>
       <div>
        for image in images:
       </div>
       <div>
        create_thumbnail(Image)
       </div>
       <div>
       </div>
       <div>
        上边这段代码的主要工作就是将遍历传入的文件夹中的图片文件，一一生成缩略图，并将这些缩略图保存到特定文件夹中。
       </div>
       <div>
       </div>
       <div>
        这我的机器上，用这一程序处理 6000 张图片需要花费 27.9 秒。
       </div>
       <div>
       </div>
       <div>
        如果我们使用 map 函数来代替 for 循环：
       </div>
       <div>
       </div>
       <div>
        import os
       </div>
       <div>
        import PIL
       </div>
       <div>
       </div>
       <div>
        from multiprocessing import Pool
       </div>
       <div>
        from PIL import Image
       </div>
       <div>
       </div>
       <div>
        SIZE = (75,75)
       </div>
       <div>
        SAVE_DIRECTORY = ‘thumbs’
       </div>
       <div>
       </div>
       <div>
        def get_image_paths(folder):
       </div>
       <div>
        return (os.path.join(folder, f)
       </div>
       <div>
        for f in os.listdir(folder)
       </div>
       <div>
        if ‘jpeg’ in f)
       </div>
       <div>
       </div>
       <div>
        def create_thumbnail(filename):
       </div>
       <div>
        im = Image.open(filename)
       </div>
       <div>
        im.thumbnail(SIZE, Image.ANTIALIAS)
       </div>
       <div>
        base, fname = os.path.split(filename)
       </div>
       <div>
        save_path = os.path.join(base, SAVE_DIRECTORY, fname)
       </div>
       <div>
        im.save(save_path)
       </div>
       <div>
       </div>
       <div>
        if __name__ == ‘__main__’:
       </div>
       <div>
        folder = os.path.abspath(
       </div>
       <div>
        ’11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840′)
       </div>
       <div>
        os.mkdir(os.path.join(folder, SAVE_DIRECTORY))
       </div>
       <div>
       </div>
       <div>
        images = get_image_paths(folder)
       </div>
       <div>
       </div>
       <div>
        pool = Pool()
       </div>
       <div>
        pool.map(creat_thumbnail, images)
       </div>
       <div>
        pool.close()
       </div>
       <div>
        pool.join()
       </div>
       <div>
       </div>
       <div>
        5.6 秒！
       </div>
       <div>
       </div>
       <div>
        虽然只改动了几行代码，我们却明显提高了程序的执行速度。在生产环境中，我们可以为 CPU 密集型任务和 IO 密集型任务分别选择多进程和多线程库来进一步提高执行速度——这也是解决死锁问题的良方。此外，由于 map 函数并不支持手动线程管理，反而使得相关的 debug 工作也变得异常简单。
       </div>
       <div>
       </div>
       <div>
        到这里，我们就实现了（基本）通过一行 Python 实现并行化。
       </div>
      </div>
      <div>
       <strong>
        注：转载文章均来自于公开网络，仅供学习使用，不会用于任何商业用途，如果侵犯到原作者的权益，请您与我们联系删除或者授权事宜，联系邮箱：contact@dataunion.org。转载数盟网站文章请注明原文章作者，否则产生的任何版权纠纷与数盟无关。
       </strong>
      </div>
      <!--content_text-->
      <div class="fenxian">
       <!-- JiaThis Button BEGIN -->
       <div class="jiathis_style_32x32">
        <p class="jiathis_button_weixin">
        </p>
        <p class="jiathis_button_tsina">
        </p>
        <p class="jiathis_button_qzone">
        </p>
        <p class="jiathis_button_cqq">
        </p>
        <p class="jiathis_button_tumblr">
        </p>
        <a class="jiathis jiathis_txt jtico jtico_jiathis" href="http://www.jiathis.com/share" target="_blank">
        </a>
        <p class="jiathis_counter_style">
        </p>
       </div>
       <!-- JiaThis Button END -->
      </div>
     </article>
     <!--content-->
     <!--相关文章-->
     <div class="xianguan">
      <div class="xianguantitle">
       相关文章！
      </div>
      <ul class="pic">
       <li>
        <a href="http://dataunion.org/24678.html">
         <img src="http://dataunion.org/wp-content/uploads/2016/06/20140917125452915416-216x200.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/24678.html" rel="bookmark" title="python3中的正则模块">
         python3中的正则模块
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/24675.html">
         <img src="http://dataunion.org/wp-content/uploads/2016/06/t015b337bd75d9ef893-161x200.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/24675.html" rel="bookmark" title="注释是恶魔，请不要再写一行注释">
         注释是恶魔，请不要再写一行注释
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/24660.html">
         <img src="http://dataunion.org/wp-content/uploads/2016/06/u16130037972892789947fm21gp0-300x157.jpg"/>
        </a>
        <a class="link" href="http://dataunion.org/24660.html" rel="bookmark" title="如何从Github上轻松安装R包">
         如何从Github上轻松安装R包
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/24654.html">
         <img src="http://dataunion.org/wp-content/uploads/2016/06/df53fac99fc53ba5a90666abcca25e6d_b-267x200.png"/>
        </a>
        <a class="link" href="http://dataunion.org/24654.html" rel="bookmark" title="简单形象又有趣地说说强大的神经网络">
         简单形象又有趣地说说强大的神经网络
        </a>
       </li>
      </ul>
     </div>
     <!--相关文章-->
     <div class="comment" id="comments">
      <!-- You can start editing here. -->
      <!-- If comments are open, but there are no comments. -->
      <div class="title">
       期待你一针见血的评论，Come on！
      </div>
      <div id="respond">
       <p>
        不用想啦，马上
        <a href="http://dataunion.org/wp-login.php?redirect_to=http%3A%2F%2Fdataunion.org%2F24295.html">
         "登录"
        </a>
        发表自已的想法.
       </p>
      </div>
     </div>
     <!-- .nav-single -->
    </div>
    <!--Container End-->
    <aside id="sitebar">
     <div class="sitebar_list2">
      <div class="wptag">
       <span class="tagtitle">
        热门标签+
       </span>
       <div class="tagg">
        <ul class="menu" id="menu-%e5%8f%8b%e6%83%85%e9%93%be%e6%8e%a5">
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1605" id="menu-item-1605">
          <a href="http://taidizh.com/">
           泰迪智慧
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20884" id="menu-item-20884">
          <a href="http://www.transwarp.cn/">
           星环科技
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-3538" id="menu-item-3538">
          <a href="http://datall.org/">
           珈和遥感
          </a>
         </li>
         <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-20888" id="menu-item-20888">
          <a href="http://www.chinahadoop.cn/">
           小象学院
          </a>
         </li>
        </ul>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <div class="textwidget">
       <div align="center">
        <a href="http://study.163.com/course/courseMain.htm?courseId=991022" target="_blank">
         <img src="http://dataunion.org/wp-content/uploads/2016/03/dv.jpg"/>
        </a>
       </div>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       文章分类
      </h4>
      <div class="tagcloud">
       <a class="tag-link-44" href="http://dataunion.org/category/industry/demo" style="font-size: 10.204724409449pt;" title="4个话题">
        Demo展示
       </a>
       <a class="tag-link-31" href="http://dataunion.org/category/experts" style="font-size: 15.826771653543pt;" title="52个话题">
        专家团队
       </a>
       <a class="tag-link-870" href="http://dataunion.org/category/tech/ai" style="font-size: 19.795275590551pt;" title="273个话题">
        人工智能
       </a>
       <a class="tag-link-488" href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f" style="font-size: 8pt;" title="1个话题">
        加入数盟
       </a>
       <a class="tag-link-869" href="http://dataunion.org/category/tech/viz" style="font-size: 17.204724409449pt;" title="93个话题">
        可视化
       </a>
       <a class="tag-link-30" href="http://dataunion.org/category/partners" style="font-size: 10.645669291339pt;" title="5个话题">
        合作伙伴
       </a>
       <a class="tag-link-889" href="http://dataunion.org/category/parterc" style="font-size: 11.582677165354pt;" title="8个话题">
        合作会议
       </a>
       <a class="tag-link-104" href="http://dataunion.org/category/books" style="font-size: 12.96062992126pt;" title="15个话题">
        图书
       </a>
       <a class="tag-link-220" href="http://dataunion.org/category/tech/base" style="font-size: 19.850393700787pt;" title="281个话题">
        基础架构
       </a>
       <a class="tag-link-219" href="http://dataunion.org/category/tech/analysis" style="font-size: 19.409448818898pt;" title="232个话题">
        数据分析
       </a>
       <a class="tag-link-887" href="http://dataunion.org/category/tech/dm" style="font-size: 13.291338582677pt;" title="17个话题">
        数据挖掘
       </a>
       <a class="tag-link-34" href="http://dataunion.org/category/tech" style="font-size: 20.732283464567pt;" title="404个话题">
        文章
       </a>
       <a class="tag-link-1" href="http://dataunion.org/category/uncategorized" style="font-size: 22pt;" title="693个话题">
        未分类
       </a>
       <a class="tag-link-4" href="http://dataunion.org/category/events" style="font-size: 14.503937007874pt;" title="29个话题">
        活动
       </a>
       <a class="tag-link-890" href="http://dataunion.org/category/tech/%e6%b7%b1%e5%ba%a6%e5%ad%a6%e4%b9%a0" style="font-size: 10.204724409449pt;" title="4个话题">
        深度学习
       </a>
       <a class="tag-link-221" href="http://dataunion.org/category/tech/devl" style="font-size: 18.968503937008pt;" title="193个话题">
        编程语言
       </a>
       <a class="tag-link-888" href="http://dataunion.org/category/career" style="font-size: 15.661417322835pt;" title="48个话题">
        职业规划
       </a>
       <a class="tag-link-5" href="http://dataunion.org/category/jobs" style="font-size: 14.11811023622pt;" title="25个话题">
        职位
       </a>
       <a class="tag-link-871" href="http://dataunion.org/category/industry" style="font-size: 15.716535433071pt;" title="49个话题">
        行业
       </a>
       <a class="tag-link-613" href="http://dataunion.org/category/industry/case" style="font-size: 16.984251968504pt;" title="84个话题">
        行业应用
       </a>
       <a class="tag-link-885" href="http://dataunion.org/category/industry/news" style="font-size: 17.425196850394pt;" title="102个话题">
        行业资讯
       </a>
       <a class="tag-link-10" href="http://dataunion.org/category/training" style="font-size: 14.228346456693pt;" title="26个话题">
        课程
       </a>
       <a class="tag-link-16" href="http://dataunion.org/category/sources" style="font-size: 15.661417322835pt;" title="48个话题">
        资源
       </a>
      </div>
     </div>
     <div class="sitebar_list">
      <h4 class="sitebar_title">
       功能
      </h4>
      <ul>
       <li>
        <a href="http://dataunion.org/wp-login.php?action=register">
         注册
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/wp-login.php">
         登录
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/feed">
         文章
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="http://dataunion.org/comments/feed">
         评论
         <abbr title="Really Simple Syndication">
          RSS
         </abbr>
        </a>
       </li>
       <li>
        <a href="https://cn.wordpress.org/" title="基于WordPress，一个优美、先进的个人信息发布平台。">
         WordPress.org
        </a>
       </li>
      </ul>
     </div>
    </aside>
    <div class="clear">
    </div>
   </div>
   <!--main-->
   ﻿
   <footer id="dibu">
    <div class="about">
     <div class="right">
      <ul class="menu" id="menu-%e5%ba%95%e9%83%a8%e8%8f%9c%e5%8d%95">
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18024" id="menu-item-18024">
        <a href="http://dataunion.org/category/partners">
         合作伙伴
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20881" id="menu-item-20881">
        <a href="http://dataunion.org/contribute">
         文章投稿
        </a>
       </li>
       <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-20872" id="menu-item-20872">
        <a href="http://dataunion.org/category/%e5%8a%a0%e5%85%a5%e6%95%b0%e7%9b%9f">
         加入数盟
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-22441" id="menu-item-22441">
        <a href="http://dataunion.org/f-links">
         友情链接
        </a>
       </li>
       <li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-20874" id="menu-item-20874">
        <a href="http://dataunion.org/aboutus">
         关于数盟
        </a>
       </li>
      </ul>
      <p class="banquan">
       数盟社区        ，
        做最棒的数据科学社区
      </p>
     </div>
     <div class="left">
      <ul class="bottomlist">
       <li>
        <a href="http://weibo.com/DataScientistUnion  " target="_blank" 　title="">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weibo.png"/>
        </a>
       </li>
       <li>
        <a class="cd-popup-trigger" href="http://dataunion.org/24295.html#0">
         <img src="http://dataunion.org/wp-content/themes/yzipi/images/weixin.png"/>
        </a>
       </li>
      </ul>
      <div class="cd-popup">
       <div class="cd-popup-container">
        <h1>
         扫描二维码,加微信公众号
        </h1>
        <img src="http://dataunion.org/wp-content/themes/yzipi/images/2014-12-06-1515289049.png"/>
        <a class="cd-popup-close" href="http://dataunion.org/24295.html">
        </a>
       </div>
       <!-- cd-popup-container -->
      </div>
      <!-- cd-popup -->
     </div>
    </div>
    <!--about-->
    <div class="bottom">
     <a href="http://dataunion.org/">
      数盟社区
     </a>
     <a href="http://www.miitbeian.gov.cn/" rel="external nofollow" target="_blank">
      京ICP备14026740号
     </a>
     联系我们：
     <a href="mailto:contact@dataunion.org" target="_blank">
      contact@dataunion.org
     </a>
     <div class="tongji">
     </div>
     <!--bottom-->
     <div class="scroll" id="scroll" style="display:none;">
      ︿
     </div>
    </div>
   </footer>
   <!--dibu-->
  </div>
 </body>
</html>